#pragma once

#include "Logger.hpp"
#include <brpc/channel.h>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include <mutex>

namespace XKL
{
    // 封装单个服务的信道管理类
    class ServiceChannel
    {
    public:
        using ptr = std::shared_ptr<ServiceChannel>;
        using ChannelPtr = std::shared_ptr<brpc::Channel>;
        ServiceChannel(const std::string &service_name)
            : _service_name(service_name), _index(0)
        {
        }
        // 服务上线一个节点，则调用append新增一个信道
        void append(const std::string &host)
        {
            auto channel = std::make_shared<brpc::Channel>();
            brpc::ChannelOptions options;
            options.connect_timeout_ms = -1;
            options.timeout_ms = -1;
            options.max_retry = 3;
            options.protocol = "baidu_std";
            if (channel->Init(host.c_str(), &options) == -1)
            {
                LOG_ERROR("init {}-{} channel failed", _service_name, host);
                return;
            }

            std::unique_lock<std::mutex> lock(_mutex);
            _map_hosts[host] = channel;
            _channels.push_back(channel);
        }
        // 服务下线一个节点，则调用remove移除一个信道
        void remove(const std::string &host)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _map_hosts.find(host);
            if (it == _map_hosts.end())
            {
                LOG_WARN("remove {}-{} channel failed, channel not exist", _service_name, host);
                return;
            }
            for (int i = 0; i < _channels.size(); i++)
            {
                if (it->second == _channels[i])
                {
                    _channels.erase(_channels.begin() + i);
                    break;
                }
            }

            _map_hosts.erase(host);
        }
        // 通过RR轮转策略，获取channel用于发起对应服务的Rpc调用
        ChannelPtr getChannel()
        {
            if (_service_name.size() == 0)
            {
                LOG_ERROR("get Channel failed, not exist {} service channel", _service_name);
                return nullptr;
            }
            std::unique_lock<std::mutex> lock(_mutex);
            _index = (_index++) % _service_name.size();
            return _channels[_index];
        }

    private:
        int32_t _index;                                         // 当前轮转下标计数器
        std::mutex _mutex;
        std::string _service_name;                              // 服务名称
        std::vector<ChannelPtr> _channels;                      // 信道集合
        std::unordered_map<std::string, ChannelPtr> _map_hosts; // 主机地址与信道的映射关系
    };

    class ServiceManager
    {
    public:
        using ptr = std::shared_ptr<ServiceManager>;
        ServiceManager() = default;
        // 获取指定服务的节点信道
        ServiceChannel::ChannelPtr getChannel(const std::string &service_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _services.find(service_name);
            if (it == _services.end())
            {
                LOG_ERROR("get Channel failed, not exist {} service", service_name);
                return nullptr;
            }
            return it->second->getChannel();
        }
        // 声明需要关注的哪些服务的上下线
        void careServices(const std::string &service_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _cared_services.insert(service_name);
        }

        // 服务上线时调用的回调接口，将服务节点管理起来
        void onServiceOnline(const std::string &service_instance, const std::string &host)
        {
            std::string service_name = getServiceName(service_instance);
            ServiceChannel::ptr service;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if (!isCareServices(service_name))
                {
                    LOG_DEBUG("not cared service {} online", service_name);
                    return;
                }
                auto it = _services.find(service_name);
                if (it == _services.end())
                {
                    service = std::make_shared<ServiceChannel>(service_name);
                    _services[service_name] = service;
                }
                service = _services[service_name];
            }
            if (!service)
            {
                LOG_ERROR("onServiceOnline, add {} service failed", service_name);
                return;
            }
            service->append(host);
            LOG_DEBUG("{}--{} 服务上线, 进行添加管理", service_name, host);
        }
        // 服务下线时调用的回调接口，将服务信道删除
        void onServiceOffline(const std::string &service_instance, const std::string &host)
        {
            std::string service_name = getServiceName(service_instance);
            ServiceChannel::ptr service;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if (!isCareServices(service_name))
                {
                    LOG_DEBUG("not concern service {} Offline", service_name);
                    return;
                }
                auto it = _services.find(service_name);
                if (it == _services.end())
                {
                    LOG_WARN("onServiceOffline, {} service not exist", service_name);
                    return;
                }
                service = _services[service_name];
            }
            service->remove(host);
            LOG_DEBUG("{}--{} 服务下线, 进行删除管理", service_name, host);
        }

    private:
        bool isCareServices(const std::string &service_name)
        {
            return _cared_services.count(service_name);
        }

        std::string getServiceName(const std::string &service_instance)
        {
            size_t end = service_instance.rfind('/');
            if(end == std::string::npos) return service_instance;
            return service_instance.substr(0, end);
        }

    private:
        std::mutex _mutex;
        std::unordered_set<std::string> _cared_services;
        std::unordered_map<std::string, ServiceChannel::ptr> _services;
    };
}